#include "sensors_data.h"
#include "Pumping_system.h"
#include "get_file_properties.h"

#include <sys/time.h>
#include <pthread.h>
#include <wiringSerial.h>
#include <stdarg.h>
#include <unistd.h>

#include <string.h>

#include <signal.h>
#include <errno.h>

//串口打开句柄
int g_handle_send_port = 0;
int g_bef_handle_send_port = 0;

pthread_mutex_t send_Uart_Mutex;

int recvBuffCompLen = 0;
char extreData[512] = {0};

/*******************************************************************
** 函数名:     CalCrc
** 函数描述:   crc校验码，返回返回4字节的校验码，高八位放在需要添加
**             校验码的len位,第八位放在len+1位
** 参数：      crc：为0 buf：需要添加校验码的字符串 len：字符串长度
********************************************************************/
int CalCrc(int crc, const char *buf, int len)
{
    unsigned int byte;
    unsigned char k;
    unsigned short ACC, TOPBIT;
    unsigned short remainder = crc;
    TOPBIT = 0x8000;
    for (byte = 0; byte < len; ++byte)
    {
        ACC = buf[byte];
        remainder ^= (ACC << 8);
        for (k = 8; k > 0; --k)
        {
            if (remainder & TOPBIT)
            {
                remainder = (remainder << 1) ^ 0x8005;
            }
            else
            {
                remainder = (remainder << 1);
            }
        }
    }
    remainder = remainder ^ 0x0000;
    return remainder;
}

/*******************************************************************
** 函数名:     timeReset
** 函数描述:   重置树莓派系统中的时间
** 参数：      recvTimeStruct从手持端接收到的当前时间结构体
********************************************************************/
void timeReset(/*int year,int month,int day,int hour,int min,int sec*/ recvTimeStruct timeStruct)
{
    struct tm tptr;
    struct timeval tv;

    tptr.tm_year = timeStruct.years - 1900;
    tptr.tm_mon = timeStruct.months - 1;
    tptr.tm_mday = timeStruct.days;
    tptr.tm_hour = timeStruct.hours;
    tptr.tm_min = timeStruct.minutes;
    tptr.tm_sec = timeStruct.seconds;

    // printf("recvTime:%d_%d_%d-%d_%d_%d\r\n", tptr.tm_year, tptr.tm_mon, tptr.tm_mday, tptr.tm_hour, tptr.tm_min, tptr.tm_sec);
    tv.tv_sec = mktime(&tptr);
    tv.tv_usec = 0;
    int ret = settimeofday(&tv, NULL);
    printf("return:%d, %s\r\n", ret, strerror(errno));
}

/*******************************************************************
** 函数名:     open_serial
** 函数描述:   打开uart串口
********************************************************************/
void open_serial()
{
    g_handle_send_port = serialOpen(SEND_SENSORS_DATA_PORT, 115200);
    if (g_handle_send_port < 0)
    {
        printf("无法打开串口uart,请检查串口设备: %s\n", strerror(errno)); //无法打开串行设备
    }
}

/*******************************************************************
** 函数名:     open_serial
** 函数描述:   关闭uart串口
********************************************************************/
void close_serial()
{
    serialClose(g_handle_send_port); //关闭串口
}

/*******************************************************************
** 函数名:     send_data_to_uart
** 函数描述:   发送数据或者命令到uart串口
** 参数：      sendData：需要发送的数据  dataLen：数据长度  msgType：数据类型
********************************************************************/
void send_data_to_uart(char *sendData, int dataLen, char msgType)
{
    // if (msgType == '1')
    //     return;
    pthread_mutex_lock(&send_Uart_Mutex);
    char sendBuff[1024 * 128] = {0};
    WXT_Packet_Header packet_heart;
    packet_heart.mark = '$';
    packet_heart.mark1 = '@';
    packet_heart.type = msgType;
    packet_heart.msg_id = 0;
    packet_heart.padlen = dataLen + 2;

    int sendLen = dataLen + sizeof(WXT_Packet_Header);

    memcpy(sendBuff, &packet_heart, sizeof(WXT_Packet_Header));
    memcpy(sendBuff + sizeof(WXT_Packet_Header), sendData, dataLen);

    unsigned short crc = CalCrc(0, sendBuff, sendLen);
    sendBuff[sendLen] = (char)(crc >> 8);
    sendBuff[sendLen + 1] = (char)crc;
    int send_data_ = 0;
    send_data_ = write(g_handle_send_port, sendBuff, sendLen + 2);

    //  printf("实际发送给qgc数据长度==%d\n", send_data_);
    // printf("send data to uart:%s, %d, %d, %d\r\n", sendData, sendLen + 2, dataLen, sizeof(WXT_Packet_Header));
    pthread_mutex_unlock(&send_Uart_Mutex);
}

/*******************************************************************
** 函数名:     send_cmd_to_uart
** 函数描述:   命令到uart串口
** 参数：      msgId: WXT_MSG_ID命令 
********************************************************************/
void send_cmd_to_uart(WXT_MSG_ID msgId)
{
    int cmdId = msgId;
    char cmdData[10] = {0};
    memcpy(cmdData, &cmdId, sizeof(int));
    send_data_to_uart(cmdData, sizeof(int), '1');

    static msgId_I[3] = {0};
    if (msgId == START_PUMP_SUCC)
    {
        msgId_I[0] = 0;
        msgId_I[1] = 0;
        msgId_I[2] = 0;
    }
    if (msgId_I[0] == 0 && msgId == HALF_WATER_FINISH)
    {

        printf("\n保存第一次抽水\n");
        pumpSaveGpsTimeToFile();
        msgId_I[0] = 1;
    }
    if (msgId_I[1] == 0 && msgId == ONE_WATER_FINISH)
    {
        printf("\n保存第二次抽水\n");
        pumpSaveGpsTimeToFile();
        msgId_I[1] = 1;
    }
    if (msgId_I[2] == 0 && msgId == ONEHALF_WATER_FINISH)
    {
        printf("\n保存第三次次抽水\n");
        pumpSaveGpsTimeToFile();
        msgId_I[2] = 1;
    }

    printf("send_cmd_to_uart:%d\r\n", cmdId);
}

/*******************************************************************
** 函数名:     sendDataFlieList
** 函数描述:   发送数据文件列表
** 参数：      filePath: 获取文件列表的文件路径
********************************************************************/
void sendDataFlieList(char *filePath)
{
    file_list file_list_f;
    int len = sizeof(file_list);
    char listData[1024 * 128] = {0};

    memset(&file_list_f, 0, len);
    if (file_properties(&file_list_f, filePath))
    {

        int list_len = 0;
        list_len = file_list_f.count * sizeof(file_stat) + (sizeof(int) * 2);

        memcpy(listData, &file_list_f, list_len);

        printf("list_len==%d,   file_list_f.count==%d   senddata===%d \n", list_len, file_list_f.count, sizeof(listData));
        send_data_to_uart(listData, list_len, FILE_LIST);
    }
}

/*******************************************************************
** 函数名:     sendDownload_file
** 函数描述:   发送选择下载的数据
** 参数：      filePath: 要下载的文件路径 要下载的文件名字                                                                          
********************************************************************/
void sendDownload_file(char *filePath, char *downloadFile_name)
{
    FILE *fd = NULL; //储存文件描述符
    char absolutelyPath_fileName[128] = {0};
    char symbol[2] = {"/"};
    strcat(absolutelyPath_fileName, filePath);
    strcat(absolutelyPath_fileName, symbol);
    strcat(absolutelyPath_fileName, downloadFile_name);
    printf("绝对路径===%s\n\n", absolutelyPath_fileName);
    fd = fopen(absolutelyPath_fileName, "r"); //打开只读文件
    if (fd == NULL)
    {
        perror("打开文件失败\n");
        return;
    }
    int read_len = 1024;
    char data[1024 + 1] = {0};
    int len = 0;
    while (1)
    {
        /* code */
        memset(data, 0, read_len);
        len = fread(data, 1, read_len, fd); //读取文件文件
        if (!len)
        {
            printf("文件为空,%s\n", absolutelyPath_fileName);
            return;
        }
        printf("下载的文件为,%s\n", absolutelyPath_fileName);
        printf("len =%d,read_len=%d\n", len, read_len);
        if (len != read_len)
        {
            send_data_to_uart(data, len, FILE_DATA);
            printf("文件发送完成:%s\n", absolutelyPath_fileName);
            send_data_to_uart(absolutelyPath_fileName, strlen(absolutelyPath_fileName), FILE_DATA_SEND_COMPLETE);
            fclose(fd);
            break;
        }
        send_data_to_uart(data, len, FILE_DATA);
        usleep(100000);
    }
    memset(absolutelyPath_fileName, 0, sizeof(absolutelyPath_fileName));
}

/*******************************************************************
** 函数名:     handleRecvData
** 函数描述:   处理来自uart串口的数据
**参数：       recvData：获取的数据  msgType：获取的数据类型
********************************************************************/
void handleSerialData(char *recvData, char msgType, int DataLen)
{
    printf("上位机数据长度==%d\n", DataLen);
    int pumpCmd = 0;
    int MudMiningCmd=0;
        recvTimeStruct timeStru;
    static char filePath[100] = {0};
    char fileName[100] = {0};
    int dataLen = DataLen - sizeof(WXT_Packet_Header) - 2;
    switch (msgType)
    {
    case '1':
        memcpy(&pumpCmd, recvData + sizeof(WXT_Packet_Header), sizeof(int));
        // printf("pumpCmd:%d\r\n", pumpCmd);
        implement_pump_cmd(pumpCmd);
        break;
    case '2':
        memcpy(&timeStru, recvData + sizeof(WXT_Packet_Header), sizeof(recvTimeStruct));
        timeReset(timeStru);
        //  printf("time:%d, %d, %d\r\n", timeStru.years, timeStru.months, timeStru.days);
        break;
    case FILE_LIST:
        memset(&filePath, 0, sizeof(filePath));
        memcpy(&filePath, recvData + sizeof(WXT_Packet_Header), dataLen);
        printf("filePath==%s\n", filePath);
        printf("a====%d   b===%d   c===%d   d=====%d\n", sizeof(filePath), dataLen, sizeof(WXT_Packet_Header), DataLen);
        sendDataFlieList(filePath);
        break;
    case FILE_DATA:
        memcpy(&fileName, recvData + sizeof(WXT_Packet_Header), dataLen);
        printf("fileName==%s\n", fileName);
        sendDownload_file(filePath, fileName);
        break;
    case '5':
        memcpy(&MudMiningCmd, recvData + sizeof(WXT_Packet_Header), sizeof(int));

        printf("\n采泥==%d\n", MudMiningCmd);
        set_Retractor_cmd(MudMiningCmd);

        break;
        default:
        break;
    }
}

/*******************************************************************
** 函数名:     recv_data_from_uart
** 函数描述:   接收来自uart串口的数据
********************************************************************/
void recv_data_from_uart()
{
    int i = 0;
    int j = 0;
    char recvBuff[512] = {0};
    WXT_Packet_Header packet_heart;

    while (1)
    {
        if (serialDataAvail(g_handle_send_port) >= 16)
        {
            // recvBuff[i]  = serialGetchar(g_handle_send_port);
            // // printf("%x, %d\r\n", recvBuff[i], i);
            // if (i >= sizeof(WXT_Packet_Header))
            // {
            //     if(recvBuffCompLen == 0)
            //     {
            //         if(recvBuff[0] == '$' && recvBuff[1] == '@')
            //         {
            //             memset(&packet_heart, 0, sizeof(WXT_Packet_Header));
            //             memcpy(&packet_heart, recvBuff, sizeof(WXT_Packet_Header));
            //             recvBuffCompLen = sizeof(WXT_Packet_Header) + packet_heart.padlen;
            //             printf("WXT_Packet_Header::%d, %d, %c, %d, %s\r\n", i, packet_heart.padlen, packet_heart.type, recvBuffCompLen, recvBuff);
            //         }

            //     }
            //     else
            //     {
            //         if (i+1 == recvBuffCompLen)
            //         {
            //             unsigned short result = CalCrc(0, recvBuff, i+1);
            //             printf("%d, %c\r\n", result,recvBuff);
            //             if (result == 0)
            //             {
            //                 handleSerialData(recvBuff, packet_heart.type);
            //             }
            //             i = 0;
            //             memset(recvBuff, 0, sizeof(recvBuff));
            //             recvBuffCompLen = 0;
            //             continue;
            //         }
            //     }

            // }
            // i++;

            usleep(20000);
            memset(recvBuff, 0, sizeof(recvBuff));
            int len = read(g_handle_send_port, recvBuff, 512);
            char *msgHeart = strstr(recvBuff, "$@");
            if (msgHeart == NULL)
            {
                return;
            }
            memset(&packet_heart, 0, sizeof(WXT_Packet_Header));
            memcpy(&packet_heart, msgHeart, sizeof(WXT_Packet_Header));
            recvBuffCompLen = sizeof(WXT_Packet_Header) + packet_heart.padlen;
            printf("%s, %d, %d\r\n", msgHeart, recvBuffCompLen, len);
            if (len >= recvBuffCompLen)
            {
                int extreLen = len - recvBuffCompLen;
                unsigned short result = CalCrc(0, msgHeart, recvBuffCompLen);
                printf("%d, %c\r\n", result, msgHeart);
                if (result == 0)
                {
                    handleSerialData(msgHeart, packet_heart.type, recvBuffCompLen);
                }
            }
            // else if( len > recvBuffCompLen)
            // {
            //     int extreLen = len - recvBuffCompLen;
            //     memcpy(extreData, recvBuff + recvBuffCompLen, extreLen);
            // }
            // else
            // {
            //     memcpy(extreData, recvBuff, len);
            // }
        }
        usleep(200000);
    }
}

int main(int argc, char *argv[])
{

    pthread_t serial_recv_thread_id;
    open_serial();
    sounding_data_init();
    pump_data_init();
    getSensorsDataCallBack(send_data_to_uart);
    inin_Retractor();//收放器初始化
    int initRet = raspberry_gpio_init_cb(send_cmd_to_uart);

    if ((pthread_create(&serial_recv_thread_id, NULL, recv_data_from_uart, NULL)) == -1)
    {
        printf("create update send data thread error!\n");
    }
    while (1)
    {
        //测试
        // send_cmd_to_uart(HALF_WATER_START);
        //
        sleep(10);
    }
}
